<?php

declare(strict_types=1);

namespace App\Utils\Encrypt;

use App\Master\Enum\RedisKeyEnum;
use App\Utils\RedisUtil;

class Token
{
    // 过期时间
    private static int $exp = 2 * 24 * 60 * 60;
    private static ?string $key = null;
    private static bool $is_sso = true;// 是否开启单点登录:true=是;false=否

    /**
     * 获取加密key
     * @return string
     */
    private static function getKey(): string
    {
        if (self::$key === null) {
            self::$key = md5(config('app.key'));
        }
        return self::$key;
    }

    /**
     * 创建token
     * @param array $data
     * @return string
     */
    public static function create(array $data,int $exp = 0): string
    {
        $exp = $exp ?: self::$exp;
        $data = array_merge($data,[
            'iat' => time(),// 签发时间
            'exp' => time() + $exp,// 过期时间
        ]);
        $dataJson = json_encode($data, JSON_UNESCAPED_UNICODE);
        $token = Aes::encode($dataJson, self::getKey());

        // 校验唯一token，单点登录
        if (self::$is_sso === true) {
            $token_key = key($data);
            $token_id = (string)reset($data);
            RedisUtil::getInstance(RedisKeyEnum::TOKEN_ONCE, $token_key, $token_id)->setex($token, $exp);
        }

        return $token;
    }

    /**
     * 验证token是否有效
     * @param string $token
     * @return false|mixed
     */
    public static function check(string $token)
    {
        //验证token
        if (!$data = Aes::decode($token, self::getKey())) {
            return false;
        }
        $data = json_decode($data,true);

        // 校验唯一token，单点登录
        if (self::$is_sso === true){
            $token_key = key($data);
            $token_id = (string)reset($data);
            if (!$userToken = RedisUtil::getInstance(RedisKeyEnum::TOKEN_ONCE,$token_key,$token_id)->get()){
                return false;
            }
            if ($userToken != $token){
                return false;
            }
        }

        return $data;
    }

    /**
     * 删除token
     * 仅开启单点登录时 可用
     * @param array $data 生成token时传递的参数
     * @return bool
     */
    public static function remove(array $data)
    {
        // 单点登录 删除登录状态
        if (self::$is_sso === true){
            $token_key = (string)key($data);
            $token_id = (string)reset($data);
            //验证token
            if (!RedisUtil::getInstance(RedisKeyEnum::TOKEN_ONCE,$token_key,$token_id)->del()) {
                return false;
            }
        }
        return true;
    }
}